package org.lisy.java.thread;

import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * 信号灯
 * 
 * @author lisy
 */
public class SemaphoreOperate {

	/**
	 * acquire(): 获取一个令牌，在获取到令牌、或者被其他线程调用中断之前线程一直处于阻塞状态
	 * acquireUninterruptibly(): 获取一个令牌，在获取到令牌之前线程一直处于阻塞状态（忽略中断）
	 * tryAcquire(): 尝试获得令牌，返回获取令牌成功或失败，不阻塞线程
	 * tryAcquire(long timeout, TimeUnit unit): 尝试获得令牌，在超时时间内循环尝试获取，直到尝试获取成功或超时返回，不阻塞线程
	 * release(): 释放一个令牌，唤醒一个获取令牌不成功的阻塞线程，被唤醒的节点会重新尝试去修改 state = state-1 的操作，如果 state >= 0 则获取令牌成功，否则重新进入阻塞队列，挂起线程 
	 * availablePermits(): 返回可用的令牌数量
	 * hasQueuedThreads(): 等待队列里是否还存在等待线程
	 * getQueueLength(): 获取等待队列里阻塞的线程数
	 * drainPermits(): 清空令牌把可用令牌数置为0，返回清空令牌的数量
	 */
	/**
	 * 调用new Semaphore(n) 方法时，默认会创建一个非公平的锁的同步阻塞队列
	 * 把初始令牌数量赋值给同步队列的state状态，state的值就代表当前所剩余的令牌数量
	 */
	private  static  Semaphore semaphore = new Semaphore(10);
	
	public static void main(String[] args) {
        for(int i = 0; i < 20; i++){
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    try {
                        System.out.println("==== " + Thread.currentThread().getName() + " arrive!");
                        if(semaphore.availablePermits() == 0){
                            System.out.println(Thread.currentThread().getName() + " wait ...");
                        }
                        semaphore.acquire();
                        System.out.println(Thread.currentThread().getName() + " enter!");
                        TimeUnit.SECONDS.sleep(new Random().nextInt(10000));
                        System.out.println(Thread.currentThread().getName() + " leave!");
                        semaphore.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "No." + (i + 1));
            thread.start();
        }
	}
}
